package com.punai.common.core.redis;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.punai.common.constant.CacheConstants;
import com.punai.common.core.domain.entity.SysPnDictionary;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.util.Collection;
import java.util.Set;

/**   
 * 说明：字典緩存
 */
@Component
public class PnDictCache implements InitializingBean {

	@Autowired
	private RedisTemplate<Object,Object> redisTemplate;

	private BoundZSetOperations<Object,Object> zsetOperations;

	public BoundZSetOperations<Object,Object> getZSetOperations() {
		return zsetOperations;
	}
	
	@SuppressWarnings("unchecked")
	public <K, R> Collection<R> getMutilDic(K minCode, K maxCode) {
		if (minCode == null || maxCode == null) {
			return null;
		}
		Double nmincode = Convert.toDouble(minCode);
		if(nmincode < 0) {
			return null;
		}
		Double nmaxcode = Convert.toDouble(maxCode);
		if(nmaxcode < 0) {
			return null;
		}
		return (Collection<R>) zsetOperations.reverseRangeByScore(nmincode, nmaxcode);
	}
	
	public <K, R> R getFromCache(K key) {
		if (key == null) {
			return null;
		}
		Double ncode = Convert.toDouble(key);
		if(ncode < 0) {
			return null;
		}
		Set<Object> dics = zsetOperations.reverseRangeByScore(ncode, ncode);
		if (CollUtil.isEmpty(dics)) {
			return null;
		}
		return (R) JSONUtil.toBean(Convert.toStr(dics.iterator().next()), SysPnDictionary.class);
	}
	

	public void putInCache(SysPnDictionary object) {
		if (object == null || StrUtil.isBlank(object.getCode())) {
			return;
		}
		String code = object.getCode();
		Double ncode = Convert.toDouble(code);
		if(ncode < 0) {
			return;
		}
		Set<Object> dics = zsetOperations.reverseRangeByScore(ncode, ncode);
		if (CollUtil.isNotEmpty(dics)) {
			zsetOperations.removeRangeByScore(ncode, ncode);
		}
		this.zsetOperations.add(JSONUtil.toJsonStr(object), ncode);
	}
	
	@SuppressWarnings("rawtypes")
	public <K> void removeChildFromCache(K key) {	
		if (key == null) {
			return;
		}
		String code = Convert.toStr(key);
		Double ncode = Convert.toDouble(key);
		if(ncode < 0) {
			return;
		}
		zsetOperations.removeRangeByScore(ncode, ncode);
		Cursor<TypedTuple<Object>> cursor = zsetOperations.scan(ScanOptions.scanOptions().count(10).build());
		cursor.forEachRemaining(obj -> {
			String dicJson = null;
			if (obj instanceof DefaultTypedTuple) {
				dicJson = Convert.toStr((((DefaultTypedTuple) obj).getValue()));
			}
			SysPnDictionary redisDic = JSONUtil.toBean(dicJson, SysPnDictionary.class);
			if (StrUtil.startWith(redisDic.getCode(), code)) {
				zsetOperations.remove(dicJson);
			}
		});
	}
	
	public <K> void removeFromCache(K key) {
		if (key == null) {
			return;
		}
		Double ncode = Convert.toDouble(key);
		if(ncode < 0) {
			return;
		}
		zsetOperations.removeRangeByScore(ncode, ncode);
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		this.zsetOperations = redisTemplate.boundZSetOps(CacheConstants.SYS_PN_DICT_KEY);
		Assert.notNull(this.zsetOperations, CacheConstants.SYS_PN_DICT_KEY + "'s zsetOperations is null.");
	}
}
